/**
 * The Free Gaming System game integration API, internal header.
 *
 * Copyright 2006 the Free Gaming System developers.
 *
 * FGS is the legal property of its developers, whose names are too
 * numerous to list here.  Please refer to the COPYRIGHT file
 * distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 */

#ifndef __FGS_INTERNAL_H__
#define __FGS_INTERNAL_H__

#include <stdlib.h>
#include <stdarg.h>

/** A structure to hold a player's information */
typedef struct fgs__player_info_t
{
  fgs_baton_t conn_baton;
  fgs_uuid_t uuid;
} fgs__player_info_t;

/** Full definition of the FGS context structure. */
struct fgs_ctx_t
{
  int proxy_fd;
  fgs_callbacks_t *cb_table;

  /* Array of known players. */
  int n_players;
  fgs__player_info_t *players;
};

/** A structure to hold proxy replies  */
typedef struct fgs__socket_reply_t
{
  char *result;
  int argc;
  char **argv;
} fgs__socket_reply_t;

/** A small macro to easily propagate errors. */
#define FGS_ERR(expr)                           \
  do {                                          \
    fgs_error_t fgs_err__temp = (expr);         \
    if (fgs_err__temp != FGS_OK)                \
      return fgs_err__temp;                     \
  } while (0)

#define FGS_ERR_WRAP(expr, err)                 \
  do {                                          \
    fgs_error_t fgs_err__temp = (expr);         \
    if (fgs_err__temp != FGS_OK)                \
      return err;                               \
  } while (0)



/** Auto-aborting wrapper arround calloc. */
void *
fgs__alloc(size_t nmemb, size_t size);

/** Auto-aborting wrapper arround realloc. */
void *
fgs__realloc(void *mem, size_t nmemb, size_t size);

/** Auto-aborting wrapper arround free. */
void
fgs__free(void *mem);

/** String duplication function, so we don't have to depend on BSD
    extensions. */
char*
fgs__strdup(char *str);


/** Return FGS_TRUE if the given callbacks table looks valid. */
fgs_error_t
fgs__callbacks_validate(fgs_callbacks_t *cb_table);

/* Read from a TCP socket (exported for use as callback for the proxy
   socket. */
fgs_error_t
fgs__callbacks_tcp_recv(fgs_baton_t b, char *s, int len, fgs_bool_t dequeue);

/* Write to a TCP socket (exported for use as callbacks for the proxy
   socket. */
fgs_error_t
fgs__callbacks_tcp_send(fgs_baton_t b, char *data, int len);


/** Connect, initialize and register the server with the proxy. */
fgs_error_t
fgs__proxy_connect(fgs_ctx_t *ctx, const char *name,
                   const char *version, int server_port);

/** Disconnect from the proxy, sending the unregister command. */
fgs_error_t
fgs__proxy_disconnect(fgs_ctx_t *ctx);

/** Get a configuration key/value pair from the proxy. */
fgs_error_t
fgs__proxy_get_config(fgs_ctx_t *ctx, char **key, char **value);


/** Send the given message to the proxy. */
fgs_error_t
fgs__socket_send(fgs_baton_t sock, conn_write_cb_t *conn_write,
                 char *command, const char *fmt, ...);

/** Read the reply from the proxy and return a reply struct. */
fgs_error_t
fgs__socket_recv(fgs_baton_t sock, conn_read_cb_t *conn_read,
                 fgs__socket_reply_t **reply);

/** Unpack a reply struct into the dynamic args provided. The reply
    struct is also freed. Set @a clear_vals to FGS_TRUE if you want the
    actual reply values to be freed as well. */
fgs_error_t
fgs__socket_free_reply(fgs__socket_reply_t *reply, fgs_bool_t clear_vals);

/** Receive the given length of data, and return it as a
 *  null-terminated string. */
fgs_error_t
fgs__socket_recv_len(fgs_baton_t sock, conn_read_cb_t *conn_read,
                     char **data, int len);


/** Create a new player entity. */
fgs_error_t
fgs__proxy_new_client(fgs_ctx_t *ctx, fgs_uuid_t *uuid, char *login,
                      char *passwd_hash, char *nonce);

/** Delete a player entity. */
fgs_error_t
fgs__proxy_del_client(fgs_ctx_t *ctx, fgs_uuid_t uuid);


/** Create a new match entity. */
fgs_error_t
fgs__proxy_new_match(fgs_ctx_t *ctx, fgs_uuid_t *uuid);

/** Delete a match entity. */
fgs_error_t
fgs__proxy_del_match(fgs_ctx_t *ctx, fgs_uuid_t uuid);


/** Send an update to a variable of an UUID-ed entity. */
fgs_error_t
fgs__proxy_update(fgs_ctx_t *ctx, char *update_type, fgs_uuid_t resource_uuid,
                  char *key, enum fgs_value_type value_type, va_list val);

/** Add the given player to the given match. */
fgs_error_t
fgs__proxy_add_to_match(fgs_ctx_t *ctx, fgs_uuid_t match_uuid,
                        fgs_uuid_t player_uuid);

/** Remove the given player from the given match. */
fgs_error_t
fgs__proxy_del_from_match(fgs_ctx_t *ctx, fgs_uuid_t match_uuid,
                          fgs_uuid_t player_uuid);

/** Propagate the given match information to the server. */
fgs_error_t
fgs__proxy_commit_match(fgs_ctx_t *ctx, fgs_uuid_t match_uuid);

/** Propagate the given player information to the server. */
fgs_error_t
fgs__proxy_commit_player(fgs_ctx_t *ctx, fgs_uuid_t player_uuid);

#endif /* __FGS_INTERNAL_H__ */
